<?php
require_once "Gi_Exception.php";
require_once "Gi_Loader.php";

//revisar si conviene mas hacerla abstracta o hacerla singleton
/**
* @desc Clase para generar un objeto singleton que de propiedades de singleton a clases no definidas como singleton
*/
final class Gi_Singleton {
  /**
  * @desc repositorio de objetos que estan como singleton
  */
  private static $_obj = array();
  /**
  * @desc Instancia singleton de esta clase
  */
  //private static $_instance = null;
  
  //constructon privado para hacer singleton la clase
  private function __construct () {
    
  }
  // para evitar clonado del objeto
  private function __clone () {
  }
  
  /**
  * @desc Obtiene la instancia singleton del objeto singleton
  */
  /*public static function get_instance () {
    if  (self::$_instance === null) {
      self::$_instance = new self();
    }
    return self::$_instance;
  } */
 
  /**
  * @desc genera un objeto singleton
  * @param El nombre d4e la clase a instanciar
  * @param de momento soporta clases con hasta 3 parametros en el constructor hay que pasarlos como si se los pasaran al constructor de la clase
  * @return bool
  */
  public static function create_singleton ($class) {
    //si no se recibe un string tiramos una excepcion
    if (!is_string($class))   
      throw new Gi_Exception("El parametro debe ser un string");
      
    //revisamos si no hay un objeto de la clase como singleton si lo hay tiramos una excepcion
    if (null !== self::$_obj[$class]) {
      throw new Exception("Ya existe una instancia de $class");
      return false;
    }
    
    //revisamos si la clase esta cargada  
    if (!class_exists($class)) {      
      //si no esta cagada la cargamos
      try {
        Gi_Loader::load_class($class);
      } 
      catch (Exception $e) {
        trigger_error($e->getMessage(),E_USER_ERROR);
        return false;
      }
    }
    
    //comprabamos que el objeto no este ya instanciado
    if (isset(self::$_obj[$class])) {
      return true;
    }
    
    $param_count = func_num_args() - 1; //el primero es el nombre de la clase
    $args = func_get_args();
    
    //reveer esta implentacion tiene que haber algo mas generico
    switch ($param_count) {
      case 0:
        self::$_obj[$class] = new $class();
        break;
      case 1 :
        self::$_obj[$class] = new $class($args[1]);
        break;
      case 2 :
        self::$_obj[$class] = new $class($args[1],$args[2]);
        break;
      case 3 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3]);
        break;
      case 4 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4]);
        break;
      case 5 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5]);
        break;
      case 6 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5],$args[6]);
        break;
      case 7 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5],$args[6],$args[7]);
        break;
      case 8 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5],$args[6],$args[7],$args[8]);
        break;
      case 9 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5],$args[6],$args[7],$args[8],$args[9]);
        break;
      case 10 :
        self::$_obj[$class] = new $class($args[1],$args[2],$args[3],$args[4],$args[5],$args[6],$args[7],$args[8],$args[9],$args[10]);
        break;
      default :
        Throw new Gi_Exception("Este objeto de momento solo soporta clases con hasta 10 parametros");
        break;
    }
    return true;
  }
  
  /**
  * @desc Obtiene la instancia del objeto
  * @param string nombre de la clase
  * @return el objeto o false
  */
  public static function get_object ($class) {
    //si no se recibe un string tiramos una excepcion
    if (!is_string($class))   
      throw new Gi_Exception("El parametro debe ser un string");
    
    if (isset(self::$_obj[$class])) 
      return self::$_obj[$class];
    else
      return false;
  }
  
  /**
  * @desc esta funcion borra objetos del array de objetos de la funcion
  * @param null|string|array null borra todo string borra un clase dada array borra todas las clases del array
  */
  public static function reset ($class = null) {
    if (is_string($class))   
      self::$_obj[$class] = null;
    if (is_array ($class)) {
      foreach ($class as $item) {
        self::$_obj[$item] = null;
      }
    }
    else if ($class === null) {
      self::$_obj = array();
    }
    else {
      throw new Gi_Exception("El parametro debe ser NULL, string o array")
    }
    return true;
  } 
}